from common.contanst import Exchange
from common.exchanges import DeribitPublicService, BinancePublicService, DeribitPriService, BinancePriService
from common.exchanges.entities import AuthInfo


class ExchangeServiceManager:
    __pub_instances = {}
    __pri_instances = {}
    __env = None
    __logger = None
    __default_exchange = None

    @classmethod
    def config(cls, env, logger, default_exchange=Exchange.DERIBIT):
        if cls.__env is None:
            cls.__env = env
        elif cls.__env != env:
            raise ValueError('exchange public env is set, can not repeat set')
        if not cls.__logger:
            cls.__logger = logger
        if not cls.__default_exchange:
            cls.__default_exchange = default_exchange

    @classmethod
    def pub(cls,):
        return cls.pub_factory(cls.__default_exchange)

    @classmethod
    def init_pub_service(cls, exchanges, base_currencies, margin_currencies):
        for exchange in exchanges:
            service = cls.pub_factory(exchange)
            service.init_quote_catcher(base_currencies, margin_currencies)
        pass

    @classmethod
    def pub_factory(cls, exchange, ):
        if not cls.__env:
            raise ValueError('exchange service manager must be configured.')

        _instance = cls.__pub_instances.get(exchange)
        if not _instance:
            if exchange == Exchange.DERIBIT:
                _instance = DeribitPublicService(env=cls.__env, logger=cls.__logger)
            elif exchange == Exchange.BINANCE:
                _instance = BinancePublicService(env=cls.__env, logger=cls.__logger)
            else:
                raise ValueError(f'exchange {exchange} is not support for public service')
            cls.__pub_instances[exchange] = _instance
        return _instance

    @classmethod
    def pri_factory(cls, exchange, auth_info: AuthInfo, cache=True):
        if not cls.__env:
            raise ValueError('exchange service manager must be configured.')

        key = f'{exchange}:{auth_info.key()}'
        _instance = cls.__pri_instances.get(key)
        if not _instance:
            if exchange == Exchange.DERIBIT:
                _instance = DeribitPriService(env=cls.__env, auth_info=auth_info, logger=cls.__logger)
            elif exchange == Exchange.BINANCE:
                _instance = BinancePriService(env=cls.__env, auth_info=auth_info, logger=cls.__logger)
            else:
                raise ValueError(f'exchange {exchange} is not support for pri service')
            if cache:
                cls.__pri_instances[key] = _instance
        return _instance

    @classmethod
    def pri_save(cls, exchange, auth_info: AuthInfo, service):
        if not cls.__env:
            raise ValueError('exchange service manager must be configured.')

        key = f'{exchange}:{auth_info.key()}'
        cls.__pri_instances[key] = service
